/**
 * <p>文件名:		BasicService.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 */

package com.caits.lbs.framework.services.hessian.server.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.beans.BeansException;
import org.springframework.util.Assert;

import com.caits.lbs.framework.Constants;
import com.caits.lbs.framework.log.CommonLogFactory;
import com.caits.lbs.framework.services.hessian.server.IHessianBaseService;
import com.caits.lbs.framework.utils.ClassUtils;
import com.caits.lbs.framework.utils.Dom4jXmlUtil;
import com.caits.lbs.framework.utils.GZipUtil;
import com.caits.lbs.framework.utils.SpringUtils;
import com.common.ajax.server.IRequest;
import com.common.ajax.server.RequestParser;
import com.common.ajax.server.SessionMap;
import com.opensymphony.xwork2.ActionContext;

/**
 * <p>
 * BasicService
 * </p>
 * <p>
 * 基本hessian服务实现
 * </p>
 * 
 * @author 周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @version 1.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhb</td>
 *          <td>2010-11-16 下午02:28:43</td>
 *          </tr>
 *          <tr>
 *          <tr>
 *          <td>1.0.0</td>
 *          <td>add jmx and memcache test</td>
 *          <td>sxd</td>
 *          <td>2011-01-05 16:19</td>
 *          </tr>
 *          </tr>
 *          </table>
 */
public class BasicServiceImpl implements IHessianBaseService {

	private int money = 1000;
	public static final int ERR_SUCCESS = 0;
	public static final int ERR_USER_PASS_ERR = -1;
	public static final int ERR_USER_NOTEXISTS = -2;
	public static final int ERR_INVALID_PARAM = -4;
	public static final int ERR_INTERNAL = -5;
	
	public static final String MSG_AUTH_FAILED = "用户名或密码错";
	public static final String MSG_NOACCESS = "权限不足";
	public static final String MSG_KEYVIOLATION = "关键字冲突";
	public static final String MSG_ARRAYISNULL = "传入的数组不包含任何元素";
	public static final String MSG_INTERNAL = "内部错误";
	public static final String MSG_INVALID_PARAM = "传入的参数不合法";
	public static final String MSG_UNKNOWN = "未知";
	/** 自定义session池 */
	protected SessionMap sessionMap = new SessionMap(getHttpRequest().getSession());

	/** 日志记录器 */
	private Logger log = CommonLogFactory.getLog();

	/** 全局参数类 */
	private Constants constant =null;
	
	/** 是否验证会话 */
	private boolean bCheckSession=false;
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.zjxl.lab.hessian.service.Basic#login(java.lang.String,
	 * java.lang.String)
	 */
	public boolean validSession(String cookie) {
		log.debug("验证用户是否已登录!");
			HttpServletRequest req = getHttpRequest();
			if(req == null ){
				log.error("无法获得用户请求的上下文.");
				return false;
			}else{
				sessionMap.setHttpSession(req.getSession(true));
				Object obj = sessionMap.getAttribute(Constants.WEB_SESSION);
				Assert.notNull(obj, "用户还没有登录，请登录,ip="+req.getRemoteAddr());
				log.debug("用户 user " + obj + " 验证成功 login access. ");
				return true;
			}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.zjxl.lab.hessian.service.Basic#giveMeMoney()
	 */
	public int giveMeMoney() {
		HttpServletRequest req = getHttpRequest();
		if (req != null && req.getSession() != null
				&& req.getSession().getAttribute("user") != null)
			return money;
		return -1;// error?
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.zjxl.lab.hessian.service.Basic#increaseMyMoney()
	 */
	public Object objectService(String name, Object[] objs) throws Exception {
		log.info("==================start call objectService=============================================");
		// HttpServletRequest req = (HttpServletRequest)
		// ServiceContext.getContextRequest();
		HttpServletRequest req = getHttpRequest();
		Object obj = null;
		if (!isbCheckSession()||validSession(name)) {
			Class<?>[] classes = com.caits.lbs.framework.utils.ClassUtils
					.getAllClass4Array(objs);
			obj = getClass().getMethod(name, classes).invoke(this, objs);
		} else
			throw new Exception("Invalid User,please login first.");
		log.info("finish objectService excuted with no error.name="+name);
		return obj;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.caits.lbs.framework.services.hessian.server.IHessianBaseService#
	 * xmlService(java.lang.String, java.lang.String)
	 */
	public String xmlService(String cookie, String xmlDoc, int compress)
			throws Exception {
		log.debug("start xmlService excuting.cookie="+cookie+",xmlDoc=" + xmlDoc+",compress="+compress);
		if (!validSession(cookie))
			return RequestParser.createErrorString(cookie,ERR_USER_PASS_ERR,
					MSG_AUTH_FAILED);
		if (xmlDoc == null)
			return RequestParser.createErrorString(cookie,ERR_INVALID_PARAM, "xml内容不能为空:" + xmlDoc);
		try {
			Document requestDoc = Dom4jXmlUtil.StringTodocument(xmlDoc);
			
			Document responseDoc = null;
			responseDoc = RequestParser.parse(requestDoc, sessionMap);
			Element e = requestDoc.getRootElement();
			String className = e.attributeValue("server");
			
			IRequest iRequest = null;
			String errorMsg="";
			int result=0;
			try {
				//取得处理类
				iRequest = (IRequest) SpringUtils.getBean(className);
			} catch (BeansException ex) {
				errorMsg += ex.getMessage();
				result = IRequest.ERROR_CLASS_NOT_FOUND;
				responseDoc = RequestParser.createError(className, result, IRequest.ERROR_CLASS_NOT_FOUND_DESC+","+errorMsg);
			}
			
			responseDoc = iRequest.request(requestDoc, getSession(cookie));
			String resString = Dom4jXmlUtil.documentToString(responseDoc);
			if (compress > 0)
				resString = GZipUtil.compress(resString, "UTF-8");
			log.info("finish xmlService excuted with no error...resString=\r\n"
					+ resString.substring(0, Math.min(resString.length(), Constants.max_log_output)));
			return resString;
		} catch (Exception ex) {
			Document responseDoc = RequestParser.createError("notserver",IRequest.ERROR_RUNTIME_ACCESS,
					IRequest.ERROR_RUNTIME_DESC);
			String resString = Dom4jXmlUtil.documentToString(responseDoc);
			log.error("xmlService excuted with  error:"
					+ ex.getMessage() + "\r\nerrXml:" + resString);
			return resString;
		}
	}

	@Override
	public Document docService(String cookie, Document xmlDoc, int compress)
			throws Exception {
		log.debug("start xmlService excuting.cookie="+cookie+",xmlDoc=" + xmlDoc+",compress="+compress);
		if (!validSession(cookie))
			return RequestParser.createError(cookie,ERR_USER_PASS_ERR,
					MSG_AUTH_FAILED);
		if (xmlDoc == null)
			return RequestParser.createError(cookie,ERR_INVALID_PARAM, "xml内容不能为空:" + xmlDoc);
		try {
			
			Document responseDoc = null;
			Element e = xmlDoc.getRootElement();
			String className = e.attributeValue("server");
			
			IRequest iRequest = null;
			String errorMsg="";
			int result=0;
			try {
				//根据id查找处理bean
				iRequest = (IRequest) SpringUtils.getBean(className);
			} catch (BeansException ex) {
				errorMsg += ex.getMessage();
				result = IRequest.ERROR_CLASS_NOT_FOUND;
				responseDoc = RequestParser.createError(className, result, IRequest.ERROR_CLASS_NOT_FOUND_DESC+","+errorMsg);
			}
			
			responseDoc = iRequest.request(xmlDoc, getSession(cookie));
			String resString = Dom4jXmlUtil.documentToString(responseDoc);
			if (compress > 0)
				resString = GZipUtil.compress(resString, "UTF-8");
			log.info("finish xmlService excuted with no error...resString=\r\n");
			return responseDoc;
		} catch (Exception ex) {
			Document responseDoc = RequestParser.createError("notserver",IRequest.ERROR_RUNTIME_ACCESS,
					IRequest.ERROR_RUNTIME_DESC);
			String resString = Dom4jXmlUtil.documentToString(responseDoc);
			log.error("xmlService excuted with  error:"
					+ ex.getMessage() + "\r\nerrXml:" + resString);
			return responseDoc;
		}
	}

	/**
	 * 验证登陆有效性
	 * 
	 * @param cookie
	 *            - cookie的值
	 * @throws Exception
	 */
	protected SessionMap getSession(String cookie) throws Exception {
		Object cookieObj = sessionMap.getAttribute("Cookie");
		if ((cookieObj!=null)&&cookieObj.toString().equals(cookie)) {
			log.info("已登陆用户:" + (cookie));
			return sessionMap;
		} else {
			log.warn("未登陆用户:" + (cookie));
		}
		return sessionMap;
	}

	/**
	 * 统一获得请求 HttpServletRequest
	 * 
	 * @return
	 */
	protected HttpServletRequest getHttpRequest() {
		HttpServletRequest request = null;
		if (request == null) {
			// JSP客户端
			try {
				// TODO 如何在纯JSP发送过来请求的时候，得到request？
				request = (HttpServletRequest) com.caucho.services.server.ServiceContext
						.getContextRequest();
				if (request != null) {
					log.info("Connected a Web client with JSP.");
				}
			} catch (Exception e) {
			}
		}
		if (request == null) {
			// Struts2客户端
			try {
				request = (HttpServletRequest) ActionContext.getContext().get(
						ServletActionContext.HTTP_REQUEST);
				// request =
				// (HttpServletRequest)ServletActionContext.getRequest();
				// 把上一行的代码，变成反射的写法，是为了在不使用Struts2前台的应用中就可以不必需要Struts2的jar包了
				Class<?> c = Class.forName("org.apache.struts2.ServletActionContext");
				Method m = c.getMethod("getRequest", new Class[] {});
				request = (HttpServletRequest) m.invoke(c, new Object[] {});
				if (request != null) {
					log.info("Connected a Web client with Struts2.");
				}
			} catch (Exception e) {
			}
		}
		if (request == null) {
			// spring客户端
			try {
				// 待查询资料 TODO
				// request =
				// (HttpServletRequest)ServletActionContext.getRequest();
				// 把上一行的代码，变成反射的写法，是为了在不使用Struts2前台的应用中就可以不必需要Struts2的jar包了
				Class<?> c = Class.forName("org.apache.struts2.ServletActionContext");
				Method m = c.getMethod("getRequest", new Class[] {});
				request = (HttpServletRequest) m.invoke(c, new Object[] {});
				if (request != null) {
					log.info("Connected a Web client with spring mvc.");
				}
			} catch (Exception e) {
			}
		}
		if (request == null) {
			// .Net
			try {
				request = (HttpServletRequest) com.caucho.services.server.ServiceContext
						.getContextRequest();
				// 把上一行的代码，变成反射的写法，是为了在不使用Hessian做RPC的应用中就可以不必需要Hessian的jar包了
				// Class c;
				// c =
				// Class.forName("com.caucho.services.server.ServiceContext");
				// Method m = c.getMethod("getContextRequest", new Class[] {});
				// request = (HttpServletRequest) m.invoke(c, new Object[] {});
				if (request != null) {
					log.info("Connected a .Net client with Hessian RPC.");
				}
			} catch (Exception e) {
			}
		}
		if (request == null) {
			// Flex/AIR客户端
			try {
				// request = FlexContext.getHttpRequest();
				// 把上一行的代码，变成反射的写法，是为了在不使用Flex/AIR前台的应用中就可以不必需要Flex的jar包了
				Class<?> c = Class.forName("flex.messaging.FlexContext");
				Method m = c.getMethod("getHttpRequest", new Class[] {});
				request = (HttpServletRequest) m.invoke(c, new Object[] {});
				if (request != null) {
					log.info("Connected a Flex/AIR client with AMF RPC.");
				}
			} catch (Exception e) {
			}
		}

		String ipAddress = "";
		if (request != null) {
			ipAddress = request.getRemoteAddr();
			if ("".equals(ipAddress)) {
				log.info("Client IP Address is unknow.");
			} else {
				log.info("Client IP Address is: " + ipAddress);
			}
		}
		return request;
	}

	
	/**
	 * 推荐使用此方法 所有方法入口代理 其它公有方法将逐渐隐藏
	 * 
	 * @param methodName
	 *            方法名称,目标方法名
	 * @param objs
	 *            方法参数，无固定大小的数组，必须与目标方法完全一致
	 * @return String 记录集或者DBBroker-500...
	 * @throws Exception
	 */
	public final String methodAdapter(String methodName, Object[] objs)
			throws Exception {
		log.debug("[methodAdapter] get method name:" + methodName + " objs:"
				+ objs);
		if (methodName == null || methodName.trim().length() < 2
				|| objs == null) {
			return RequestParser.createErrorString(methodName,ERR_INVALID_PARAM,
					MSG_INVALID_PARAM);
		}
		String sRet = null;
		Method method = null;
		Class<?>[] ParamList = ClassUtils.getAllClass4Array(objs);
		try {
			method = this.getClass().getDeclaredMethod(methodName, ParamList);
		} catch (Exception e) {
			log.error("无效的调用名:" + methodName + " " + e + " " + e.getMessage());
			sRet = RequestParser.createErrorString(methodName,ERR_INTERNAL, MSG_INTERNAL);
			return sRet;
		}
		try {
			sRet = (String) method.invoke(this, objs);
		} catch (InvocationTargetException ite) {
			log.error("指令执行失败:" + methodName + " " + ite + " "
					+ ite.getMessage());
			sRet = RequestParser.createErrorString(methodName,ERR_INTERNAL, MSG_INTERNAL);
			return sRet;
		} catch (Exception e) {
			log.error("失败的指令调用:" + methodName + " " + e + " " + e.getMessage());
			sRet = RequestParser.createErrorString(methodName,ERR_INTERNAL, MSG_INTERNAL);
		}

		return sRet;
	}

	/**
	 * 设置变量 constant 的值，数据类型：Constants
	 * @param constant the constant to set
	 */
	public void setConstant(Constants constant) {
		this.constant = constant;
	}

	/**
	 * 获取变量constant的值
	 * @return the constant 数据类型 : Constants
	 */
	public Constants getConstant() {
		return constant;
	}

	/**
	 * 获取变量<code>bCheckSession</code>的值
	 * @return 返回的数据类型是<code>boolean</code>
	 */
	public boolean isbCheckSession() {
		return bCheckSession;
	}

	/**
	 * 设置变量<code> bCheckSession</code> 的值
	 * @param bCheckSession  <code>bCheckSession</code> 参数类型是<code>boolean</code>
	 */
	public void setbCheckSession(boolean bCheckSession) {
		this.bCheckSession = bCheckSession;
	}

}
